home *** CD-ROM | disk | FTP | other *** search
- #
- # This file is part of Checkbox.
- #
- # Copyright 2008 Canonical Ltd.
- #
- # Checkbox is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # Checkbox is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
- #
- import os
- import re
- import string
- import posixpath
-
- from curses.ascii import isprint
-
- from checkbox.lib.bit import get_bitmask, test_bit
- from checkbox.lib.cache import cache
- from checkbox.lib.dmi import Dmi, DmiNotAvailable
- from checkbox.lib.input import Input
- from checkbox.lib.pci import Pci
- from checkbox.lib.usb import Usb
-
- from checkbox.properties import String
- from checkbox.registry import Registry
- from checkbox.registries.command import CommandRegistry
- from checkbox.registries.link import LinkRegistry
- from checkbox.registries.map import MapRegistry
-
-
- class DeviceRegistry(Registry):
-
- def __init__(self, environment, attributes):
- super(DeviceRegistry, self).__init__()
- self._environment = environment
- self._attributes = attributes
-
- def __str__(self):
- strings = ["%s: %s" % (k, v) for k, v in self.items()
- if not isinstance(v, Registry)]
-
- return "\n".join(strings)
-
- def _get_bus(self):
- sys_path = posixpath.join("/sys%s" % self._environment["DEVPATH"], "subsystem")
- if posixpath.islink(sys_path):
- link = os.readlink(sys_path)
- if "/" in link:
- return posixpath.basename(link)
-
- return None
-
- def _get_category(self):
- if "sys_vendor" in self._attributes:
- return "SYSTEM"
-
- if "IFINDEX" in self._environment:
- return "NETWORK"
-
- if "PCI_CLASS" in self._environment:
- pci_class = self._environment["PCI_CLASS"]
- if len(pci_class) > 4:
- pci_class = pci_class[:-2]
-
- subclass_id = int(pci_class[-2:], 16)
- class_id = int(pci_class[:-2], 16)
-
- if class_id == Pci.BASE_CLASS_NETWORK:
- return "NETWORK"
-
- if class_id == Pci.BASE_CLASS_DISPLAY:
- return "VIDEO"
-
- if class_id == Pci.BASE_CLASS_SERIAL \
- and subclass_id == Pci.CLASS_SERIAL_USB:
- return "USB"
-
- if class_id == Pci.BASE_CLASS_STORAGE:
- if subclass_id == Pci.CLASS_STORAGE_SCSI:
- return "SCSI"
-
- if subclass_id == Pci.CLASS_STORAGE_IDE:
- return "IDE"
-
- if subclass_id == Pci.CLASS_STORAGE_FLOPPY:
- return "FLOPPY"
-
- if subclass_id == Pci.CLASS_STORAGE_RAID:
- return "RAID"
-
- if class_id == Pci.BASE_CLASS_COMMUNICATION \
- and subclass_id == Pci.CLASS_COMMUNICATION_MODEM:
- return "MODEM"
-
- if class_id == Pci.BASE_CLASS_INPUT \
- and subclass_id == Pci.CLASS_INPUT_SCANNER:
- return "SCANNER"
-
- if class_id == Pci.BASE_CLASS_MULTIMEDIA:
- if subclass_id == Pci.CLASS_MULTIMEDIA_VIDEO:
- return "CAPTURE"
-
- if subclass_id == Pci.CLASS_MULTIMEDIA_AUDIO \
- or subclass_id == Pci.CLASS_MULTIMEDIA_AUDIO_DEVICE:
- return "AUDIO"
-
- if class_id == Pci.BASE_CLASS_SERIAL \
- and subclass_id == Pci.CLASS_SERIAL_FIREWIRE:
- return "FIREWIRE"
-
- if class_id == Pci.BASE_CLASS_BRIDGE \
- and (subclass_id == Pci.CLASS_BRIDGE_PCMCIA \
- or subclass_id == Pci.CLASS_BRIDGE_CARDBUS):
- return "SOCKET"
-
- if "bInterfaceClass" in self._attributes:
- interface_class = int(self._attributes["bInterfaceClass"], 16)
- interface_subclass = int(self._attributes["bInterfaceSubClass"], 16)
-
- if interface_class == Usb.BASE_CLASS_AUDIO:
- return "AUDIO"
-
- if interface_class == Usb.BASE_CLASS_PRINTER:
- return "PRINTER"
-
- if interface_class == Usb.BASE_CLASS_STORAGE:
- if interface_subclass == Usb.CLASS_STORAGE_FLOPPY:
- return "FLOPPY"
-
- if interface_subclass == Usb.CLASS_STORAGE_SCSI:
- return "SCSI"
-
- if interface_class == Usb.BASE_CLASS_VIDEO:
- return "VIDEO"
-
- if interface_class == Usb.BASE_CLASS_WIRELESS:
- return "NETWORK"
-
- if "ID_TYPE" in self._environment:
- id_type = self._environment["ID_TYPE"]
-
- if id_type == "cd":
- return "CDROM"
-
- if id_type == "disk":
- return "DISK"
-
- if id_type == "video":
- return "VIDEO"
-
- if "KEY" in self._environment:
- key = self._environment["KEY"].strip("=")
- bitmask = get_bitmask(key)
-
- for i in range(Input.KEY_Q, Input.KEY_P+1):
- if not test_bit(i, bitmask):
- break
- else:
- return "KEYBOARD"
-
- if test_bit(Input.BTN_MOUSE, bitmask):
- return "MOUSE"
-
- if self._environment.get("DEVTYPE") == "disk":
- if "ID_CDROM" in self._environment:
- return "CDROM"
-
- if "ID_DRIVE_FLOPPY" in self._environment:
- return "FLOPPY"
-
- if self._environment.get("DEVTYPE") == "scsi_device":
- type = int(self._attributes.get("type", "-1"))
- if type in (0, 7, 14):
- return "DISK"
-
- if type == 1:
- return "TAPE"
-
- if type == 2:
- return "PRINTER"
-
- if type in (4, 5):
- return "CDROM"
-
- if type == 6:
- return "SCANNER"
-
- if type == 12:
- return "RAID"
-
- if self._get_product_id():
- return "OTHER"
-
- return None
-
- def _get_driver(self):
- if "DRIVER" in self._environment:
- return self._environment["DRIVER"]
-
- if "ID_USB_DRIVER" in self._environment:
- return self._environment["ID_USB_DRIVER"]
-
- return None
-
- def _get_path(self):
- return self._environment.get("DEVPATH")
-
- def _get_product_id(self):
- # pci
- if "PCI_ID" in self._environment:
- vendor_id, product_id = self._environment["PCI_ID"].split(":")
- return int(product_id, 16)
-
- # usb interface
- if "PRODUCT" in self._environment \
- and self._environment.get("DEVTYPE") == "usb_interface":
- vendor_id, product_id, revision = self._environment["PRODUCT"].split("/")
- return int(product_id, 16)
-
- # usb device and ieee1394
- for attribute in "idProduct", "model_id":
- if attribute in self._attributes:
- return int(self._attributes[attribute], 16)
-
- # pnp
- if "id" in self._attributes:
- match = re.match(r"^(?P<vendor_name>.*)(?P<product_id>[%s]{4})$"
- % string.hexdigits, self._attributes["id"])
- if match:
- return int(match.group("product_id"), 16)
-
- return None
-
- def _get_vendor_id(self):
- # pci
- if "PCI_ID" in self._environment:
- vendor_id, product_id = self._environment["PCI_ID"].split(":")
- return int(vendor_id, 16)
-
- # usb interface
- if "PRODUCT" in self._environment \
- and self._environment.get("DEVTYPE") == "usb_interface":
- vendor_id, product_id, revision = self._environment["PRODUCT"].split("/")
- return int(vendor_id, 16)
-
- # usb device
- if "idVendor" in self._attributes:
- return int(self._attributes["idVendor"], 16)
-
- # ieee1394
- vendor_id_path = posixpath.join(self._get_path(), "../vendor_id")
- if posixpath.exists(vendor_id_path):
- vendor_id = open(vendor_id_path, "r").read().strip()
- return int(vendor_id, 16)
-
- return None
-
- def _get_subproduct_id(self):
- if "PCI_SUBSYS_ID" in self._environment:
- pci_subsys_id = self._environment["PCI_SUBSYS_ID"]
- subvendor_id, subproduct_id = pci_subsys_id.split(":")
- return int(subproduct_id, 16)
-
- return None
-
- def _get_subvendor_id(self):
- if "PCI_SUBSYS_ID" in self._environment:
- pci_subsys_id = self._environment["PCI_SUBSYS_ID"]
- subvendor_id, subproduct_id = pci_subsys_id.split(":")
- return int(subvendor_id, 16)
-
- return None
-
- def _get_product(self):
- for element in ("NAME",
- "RFKILL_NAME",
- "POWER_SUPPLY_MODEL_NAME"):
- if element in self._environment:
- return self._environment[element].strip('"')
-
- for attribute in ("description",
- "model_name_kv",
- "model",
- "product_name"):
- if attribute in self._attributes:
- return self._attributes[attribute]
-
- # sound
- bus = self._get_bus()
- if bus == "sound":
- device = posixpath.basename(self._environment["DEVPATH"])
- match = re.match(r"(card|controlC|hwC|midiC)(?P<card>\d+)", device)
- if match:
- card = match.group("card")
- in_card = False
- file = open("/proc/asound/cards", "r")
- for line in file.readlines():
- line = line.strip()
- match = re.match(r"(?P<card>\d+) \[", line)
- if match:
- in_card = match.group("card") == card
-
- if in_card:
- match = re.match(r"""(?P<name>.*) """
- """at (?P<address>0x[%s]{8}) """
- """irq (?P<irq>\d+)""" % string.hexdigits, line)
- if match:
- return match.group("name")
-
- path = None
- match = re.match(r"pcmC(?P<card>\d+)D(?P<device>\d+)(?P<type>\w)",
- device)
- if match:
- path = "/proc/asound/card%s/pcm%s%c/info" % match.groups()
-
- match = re.match(r"(dsp|adsp|midi|amidi|audio|mixer)(?P<card>\d+)?",
- device)
- if match:
- card = match.group("card") or 0
- path = "/proc/asound/card%s/pcm0p/info" % card
-
- if path and posixpath.exists(path):
- file = open(path, "r")
- for line in file.readlines():
- match = re.match(r"name: (?P<name>.*)", line)
- if match:
- return match.group("name")
-
- return None
-
- def _get_vendor(self):
- if "RFKILL_NAME" in self._environment:
- return None
-
- if "POWER_SUPPLY_MANUFACTURER" in self._environment:
- return self._environment["POWER_SUPPLY_MANUFACTURER"]
-
- if "vendor" in self._attributes:
- vendor = self._attributes["vendor"]
- if not re.match(r"^0x[%s]{4}$" % string.hexdigits, vendor):
- return vendor
-
- # dmi
- if "sys_vendor" in self._attributes:
- return self._attributes["sys_vendor"]
-
- # pnp
- if "id" in self._attributes:
- match = re.match(r"^(?P<vendor_name>.*)(?P<product_id>[%s]{4})$"
- % string.hexdigits, self._attributes["id"])
- if match:
- return match.group("vendor_name")
-
- # ieee1394
- vendor_path = posixpath.join(self._get_path(), "../vendor_oui")
- if posixpath.exists(vendor_path):
- return open(vendor_path, "r").read().strip()
-
- return None
-
- def items(self):
- return (
- ("path", self._get_path()),
- ("bus", self._get_bus()),
- ("category", self._get_category()),
- ("driver", self._get_driver()),
- ("product_id", self._get_product_id()),
- ("vendor_id", self._get_vendor_id()),
- ("subproduct_id", self._get_subproduct_id()),
- ("subvendor_id", self._get_subvendor_id()),
- ("product", self._get_product()),
- ("vendor", self._get_vendor()),
- ("attributes", MapRegistry(self._attributes)),
- ("environment", MapRegistry(self._environment)),
- ("device", LinkRegistry(self)))
-
-
- class DmiDeviceRegistry(DeviceRegistry):
-
- def __init__(self, environment, attributes, category):
- super(DmiDeviceRegistry, self).__init__(environment, attributes)
- self._category = category
-
- def _get_category(self):
- return self._category
-
- def _get_path(self):
- path = super(DmiDeviceRegistry, self)._get_path()
- return posixpath.join(path, self._category.lower())
-
- def _get_product(self):
- if self._category == "CHASSIS":
- type = int(self._attributes["chassis_type"])
- return Dmi.chassis_names[type]
-
- for name in "name", "version":
- attribute = "%s_%s" % (self._category.lower(), name)
- product = self._attributes.get(attribute)
- if product and product != "Not Available":
- return product
-
- return None
-
- @DmiNotAvailable
- def _get_vendor(self):
- attribute = "%s_vendor" % self._category.lower()
- if attribute in self._attributes:
- return self._attributes[attribute]
-
- return None
-
-
- class UdevRegistry(CommandRegistry):
- """Registry for udev information."""
-
- # Command to retrieve udev information.
- command = String(default="udevadm info --export-db")
-
- def _get_attributes(self, path):
- attributes = {}
- sys_path = "/sys%s" % path
- try:
- names = os.listdir(sys_path)
- except OSError:
- return attributes
-
- for name in names:
- name_path = posixpath.join(sys_path, name)
- if name[0] == "." \
- or name in ["dev", "uevent"] \
- or posixpath.isdir(name_path) \
- or posixpath.islink(name_path):
- continue
-
- try:
- value = open(name_path, "r").read().strip()
- except IOError:
- continue
-
- value = value.split("\n")[0]
- if [c for c in value if not isprint(c)]:
- continue
-
- attributes[name] = value
-
- return attributes
-
- def _ignore_device(self, device):
- # Ignore devices without bus information
- if not device.bus:
- return True
-
- # Ignore devices without product information
- if not device.product and device.product_id is None:
- return True
-
- # Ignore invalid subsystem information
- if (device.subproduct_id is None and device.subvendor_id is not None) \
- or (device.subproduct_id is not None and device.subvendor_id is None):
- return True
-
- # Ignore virtual devices except for dmi information
- if device.bus != "dmi" \
- and "virtual" in device.path.split(posixpath.sep):
- return True
-
- return False
-
- @cache
- def items(self):
- devices = []
- line_pattern = re.compile(r"(?P<key>\w):\s*(?P<value>.*)")
- multi_pattern = re.compile(r"(?P<key>\w+)=(?P<value>.*)")
-
- for record in str(self).split("\n\n"):
- if not record:
- continue
-
- # Determine path and environment
- path = None
- environment = {}
- for line in record.split("\n"):
- match = line_pattern.match(line)
- if not match:
- raise Exception, \
- "Device line not supported: %s" % line
-
- key = match.group("key")
- value = match.group("value")
-
- if key == "P":
- path= value
- elif key == "E":
- match = multi_pattern.match(value)
- if not match:
- raise Exception, \
- "Device property not supported: %s" % value
- environment[match.group("key")] = match.group("value")
-
- # Set default DEVPATH
- environment.setdefault("DEVPATH", path)
-
- # Determine attributes
- attributes = self._get_attributes(path)
-
- if path == "/devices/virtual/dmi/id":
- device = DeviceRegistry(environment, attributes)
- devices.append(device)
- for category in "BIOS", "BOARD", "CHASSIS":
- device = DmiDeviceRegistry(environment, attributes, category)
- devices.append(device)
- else:
- device = DeviceRegistry(environment, attributes)
- devices.append(device)
-
- return [(d.path, d) for d in devices if not self._ignore_device(d)]
-
-
- factory = UdevRegistry
-